u_short calc_IP_chk(u_char *data) {
	long sum = 0;
	u_short *itr;

	itr = (u_short*)(data + 14);
	for (int i = 0; i < 5; i++) {
		sum += *itr;
		if(sum & 0x80000000)   /* if high order bit set, fold */
			sum = (sum & 0xFFFF) + (sum >> 16);
		itr++;
	}
	itr = (u_short*)(data + 26);
	for (int i = 0; i < 4; i++) {
		sum += *itr;
		if(sum & 0x80000000)   /* if high order bit set, fold */
			sum = (sum & 0xFFFF) + (sum >> 16);
		itr++;
	}
	while(sum>>16)
		sum = (sum & 0xFFFF) + (sum >> 16);
	return ~sum;
}

u_short calc_TCP_chk(const u_char *data, int len) {
	long sum = 0;
	u_short tcp_start, tcp_size;
	u_short *itr;

	/*IP Pseudo header IP*/
	itr = (u_short*)(data + 26);
	for (int i = 0; i < 4; i++) {
		sum += *itr;
		if(sum & 0x80000000)   /* if high order bit set, fold */
			sum = (sum & 0xFFFF) + (sum >> 16);
		itr++;
	}

	tcp_start = 14 + 4 * ((*(data + 14)) & 0x0F);
	tcp_size = len - 4 * ((*(data + 14)) & 0x0F);
	
//	printf("tcp_start = %d, len = %d, checksum = %04x , ", tcp_start, tcp_size, *((u_short*)(data + tcp_start + 16)));

	itr = (u_short*)(data + tcp_start);
	for (int i = 0; i < 8; i++) {
		sum += *itr;
		if(sum & 0x80000000)   /* if high order bit set, fold */
			sum = (sum & 0xFFFF) + (sum >> 16);
		itr++;
	}

	itr = (u_short*)(data + tcp_start + 18);
	for (int i = 0; i < tcp_size/2 - 9; i++) {
		sum += *itr;
		if(sum & 0x80000000)   /* if high order bit set, fold */
			sum = (sum & 0xFFFF) + (sum >> 16);
		itr++;
	}

	if (tcp_size % 2 != 0)
		sum += *(data + tcp_start + tcp_size - 1);

	sum += 0x0600;
	sum += htons(tcp_size);
	while(sum>>16)
		sum = (sum & 0xFFFF) + (sum >> 16);
	return ~sum;
}

u_short calc_UDP_chk(const u_char *data, int len) {
	long sum = 0;
	u_short udp_start, udp_size;
	u_short *itr;

	/*IP Pseudo header IP*/
	itr = (u_short*)(data + 26);
	for (int i = 0; i < 4; i++) {
		sum += *itr;
		if(sum & 0x80000000)   /* if high order bit set, fold */
			sum = (sum & 0xFFFF) + (sum >> 16);
		itr++;
	}

	udp_start = 14 + 4 * ((*(data + 14)) & 0x0F);
	udp_size = len - 4 * ((*(data + 14)) & 0x0F);

	itr = (u_short*)(data + udp_start);
	for (int i = 0; i < 3; i++) {
		sum += *itr;
		if(sum & 0x80000000)   /* if high order bit set, fold */
			sum = (sum & 0xFFFF) + (sum >> 16);
		itr++;
	}

	itr = (u_short*)(data + udp_start + 8);
	for (int i = 0; i < udp_size/2 - 4; i++) {
		sum += *itr;
		if(sum & 0x80000000)   /* if high order bit set, fold */
			sum = (sum & 0xFFFF) + (sum >> 16);
		itr++;
	}

	if (udp_size % 2 != 0)
		sum += *(data + udp_start + udp_size - 1);

	sum += 0x1100;
	sum += htons(udp_size);
	while(sum>>16)
		sum = (sum & 0xFFFF) + (sum >> 16);
	return ~sum;
}
